# wmi和htc分析 ## wmi_control_rx 分析 ### 注册`wmi_control_rx` ```c static QDF_STATUS wmi_connect_pdev_htc_service(struct wmi_soc *soc, uint32_t pdev_idx) { struct htc_service_connect_resp response; struct htc_service_connect_req connect; connect.EpCallbacks.EpRecv = wmi_control_rx /* Control path rx */; // 注册 status = htc_connect_service(soc->htc_handle, &connect, &response); } ``` ### 调用`wmi_control_rx` ```c static void do_recv_completion_pkt(HTC_ENDPOINT *pEndpoint, HTC_PACKET *pPacket) { if (!pEndpoint->EpCallBacks.EpRecv) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTC ep %d has NULL recv callback on packet %pK\n", pEndpoint->Id, pPacket)); if (pPacket) qdf_nbuf_free(pPacket->pPktContext); } else { AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("HTC calling ep %d recv callback on packet %pK\n", pEndpoint->Id, pPacket)); // 实际就是调用 wmi_control_rx pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, pPacket); } } ``` 问题谁调用了`do_recv_completion_pkt`函数,分析如下: 1. `do_recv_completion` ```c static void do_recv_completion(HTC_ENDPOINT *pEndpoint, HTC_PACKET_QUEUE *pQueueToIndicate) { HTC_PACKET *pPacket; if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { /* nothing to indicate */ return; } while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) { pPacket = htc_packet_dequeue(pQueueToIndicate); // 调用地方do_recv_completion_pkt do_recv_completion_pkt(pEndpoint, pPacket); } } ``` 那么谁又调用了`do_recv_completion`函数 ```c #ifdef HIF_SDIO void epping_refill(void *ctx, HTC_ENDPOINT_ID Endpoint) { if (!HTC_QUEUE_EMPTY(&queue)) { /* add packets */ htc_add_receive_pkt_multiple(pEpping_ctx->HTCHandle, &queue); { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); HTC_PACKET *pFirstPacket = htc_get_pkt_at_head(pPktQueue); pEndpoint = &target->endpoint[pFirstPacket->Endpoint]; /* store receive packets */ HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue,pPktQueue); // 调用do_recv_completion地方 do_recv_completion(pEndpoint, pPktQueue); } } } #endif /* HIF_SDIO */ ``` 总结,从这里可以看出,这个步骤基本用不到目前,因为需要定义HIF_SDIO宏 2. `htc_rx_completion_handler` ```c QDF_STATUS htc_rx_completion_handler(void *Context, qdf_nbuf_t netbuf, uint8_t pipeID) { // 调用地方do_recv_completion_pkt do_recv_completion_pkt(pEndpoint, pPacket); } ``` `htc_rx_completion_handler`函数是在htc_create函数中注册到`htcCallbacks.rxCompletionHandler`里面的,如下: ```c HTC_HANDLE htc_create(void *ol_sc, struct htc_init_info *pInfo, qdf_device_t osdev, uint32_t con_mode) { hcCallbacks.Context = target; //注册htc_rx_completion_handler的地方 htcCallbacks.rxCompletionHandler = htc_rx_completion_handler; htcCallbacks.txCompletionHandler = htc_tx_completion_handler; htcCallbacks.txResourceAvailHandler = htc_tx_resource_avail_handler; htcCallbacks.fwEventHandler = htc_fw_event_handler; htcCallbacks.update_bundle_stats = htc_update_rx_bundle_stats; } ``` 下面分析何时调用`htcCallbacks.rxCompletionHandler` ```c static inline void hif_ce_do_recv(struct hif_msg_callbacks *msg_callbacks, qdf_nbuf_t netbuf, int nbytes, struct HIF_CE_pipe_info *pipe_info) { if (nbytes <= pipe_info->buf_sz) { qdf_nbuf_set_pktlen(netbuf, nbytes); // 调用 htcCallbacks.rxCompletionHandler的 地方 // 即 实际调用htc_rx_completion_handler的地方 msg_callbacks-> rxCompletionHandler(msg_callbacks->Context, netbuf, pipe_info->pipe_num); } else { hif_err("Invalid Rx msg buf: %pK nbytes: %d", netbuf, nbytes); qdf_nbuf_free(netbuf);c } } ``` 谁又调用`hif_ce_do_recv` ,接下来分析 ```c static void hif_pci_ce_recv_data(struct CE_handle *copyeng, void *ce_context, void *transfer_context, qdf_dma_addr_t CE_data, unsigned int nbytes, unsigned int transfer_id, unsigned int flags) { if (scn->target_status == TARGET_STATUS_RESET)c qdf_nbuf_free(transfer_context); else hif_ce_do_recv(msg_callbacks, transfer_context, nbytes, pipe_info); } ``` 接下来分析谁调用了`hif_pci_ce_recv_data`函数 - 注册`hif_pci_ce_recv_data`的地方 ```c static int hif_completion_thread_startup_by_ceid(struct HIF_CE_state *hif_state,int pipe_num) { ce_recv_cb_register(pipe_info->ce_hdl, hif_pci_ce_recv_data, //注册的地方 pipe_info,attr.flags & CE_ATTR_DISABLE_INTR); { //函数原型 void ce_recv_cb_register(struct CE_handle *copyeng, CE_recv_cb fn_ptr, void *CE_recv_context, int disable_interrupts) { CE_state->recv_context = CE_recv_context; // 赋值的地方 CE_state->recv_cb = hif_pci_ce_recv_data CE_state->recv_cb = fn_ptr; } } } ``` - 调用CE_state->recv_cb的地方,即调用`hif_pci_ce_recv_data`的地方 ```c void ce_engine_service_reg(struct hif_softc *scn, int CE_id) { while (hif_state->ce_services->ce_completed_recv_next_nolock (CE_state, &CE_context, &transfer_context, &buf, &nbytes, &id, &flags) == QDF_STATUS_SUCCESS) { // 调用 hif_pci_ce_recv_data的地方 CE_state->recv_cb((struct CE_handle *)CE_state, CE_context, transfer_context, buf, nbytes, id, flags); } } ``` - 接下来分析`ce_engine_service_reg`调用的地方 - 注册 ```c struct CE_handle *ce_init(struct hif_softc *scn, unsigned int CE_id, struct CE_attr *attr) { CE_state->scn = scn; CE_state->service = ce_engine_service_reg; // 注册地方 } ``` - 调用 ```c int ce_per_engine_service(struct hif_softc *scn, unsigned int CE_id) { // 调用地方,也就是调用ce_engine_service_reg的地方 CE_state->service(scn, CE_id); } ``` - 接下来分析`ce_per_engine_service`调用地方 - ce_poll_timeout ``` static void ce_poll_timeout(void *arg) { struct CE_state *CE_state = (struct CE_state *)arg; if (CE_state->timer_inited) { ce_per_engine_service(CE_state->scn, CE_state->id); qdf_timer_mod(&CE_state->poll_timer, CE_POLL_TIMEOUT); } } ``` - ce_per_engine_service_any ``` void ce_per_engine_service_any(int irq, struct hif_softc *scn) { int CE_id; uint32_t intr_summary; if (Q_TARGET_ACCESS_BEGIN(scn) < 0) return; if (!qdf_atomic_read(&scn->tasklet_from_intr)) { for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; if (qdf_atomic_read(&CE_state->rx_pending)) { qdf_atomic_set(&CE_state->rx_pending, 0); ce_per_engine_service(scn, CE_id); } } Q_TARGET_ACCESS_END(scn); return; } intr_summary = CE_INTERRUPT_SUMMARY(scn); for (CE_id = 0; intr_summary && (CE_id < scn->ce_count); CE_id++) { if (intr_summary & (1 << CE_id)) intr_summary &= ~(1 << CE_id); else continue; /* no intr pending on this CE */ ce_per_engine_service(scn, CE_id); } Q_TARGET_ACCESS_END(scn); } ``` - static void ce_tasklet(unsigned long data) ``` static void ce_tasklet(unsigned long data) { ce_per_engine_service(scn, tasklet_entry->ce_id); } ``` tasklet初始化的过程如下: ```c int hif_pci_bus_configure(struct hif_softc *hif_sc) { status = hif_config_ce(hif_sc); } int hif_config_ce(struct hif_softc *scn) { for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { struct CE_attr *attr; pipe_info = &hif_state->pipe_info[pipe_num]; attr = &hif_state->host_ce_config[pipe_num]; if (attr->flags & CE_ATTR_INIT_ON_DEMAND) continue; if (hif_config_ce_by_id(scn, pipe_num)) goto err; } } int hif_config_ce_by_id(struct hif_softc *scn, int pipe_num) { ce_tasklet_init(hif_state, (1 << pipe_num)); // 初始化的地方 ce_register_irq(hif_state, (1 << pipe_num)); init_tasklet_worker_by_ceid(hif_hdl, pipe_num); } ``` ```c void ce_tasklet_init(struct HIF_CE_state *hif_ce_state, uint32_t mask) { int i; for (i = 0; i < CE_COUNT_MAX; i++) { if (mask & (1 << i)) { hif_ce_state->tasklets[i].ce_id = i; hif_ce_state->tasklets[i].inited = true; hif_ce_state->tasklets[i].hif_ce_state = hif_ce_state; tasklet_init(&hif_ce_state->tasklets[i].intr_tq, ce_tasklet, (unsigned long)&hif_ce_state->tasklets[i]); } } } ``` - ce_poll_reap_by_id ``` static int ce_poll_reap_by_id(struct hif_softc *scn, enum ce_id_type ce_id) { ce_per_engine_service(scn, ce_id); } ``` - - 3. `htc_flush_rx_hold_queue` ```c void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint) { HTC_PACKET *pPacket; LOCK_HTC_RX(target); while (1) { pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue); if (!pPacket) break; UNLOCK_HTC_RX(target); pPacket->Status = QDF_STATUS_E_CANCELED; pPacket->ActualLength = 0; AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("Flushing RX packet:%pK, length:%d, ep:%d\n", pPacket, pPacket->BufferLength, pPacket->Endpoint)); /* give the packet back */ // 调用地方do_recv_completion_pkt do_recv_completion_pkt(pEndpoint, pPacket); LOCK_HTC_RX(target); } UNLOCK_HTC_RX(target); } ```